#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "os.h"
#include "filterrecord.h"

#define MAX_DATA_CNT 5

static unsigned char u8Init = 0;

static unsigned int s_u32FilterRecordMutex = 0;
static unsigned int s_u32FilterSockMutex;
static unsigned int s_u32FilterRecordSemCnt = 0;

typedef struct
{
	unsigned char* 	m_pu8Data;
	unsigned int		m_u32Len;
}filter_record_data_t;

filter_record_data_t astData[MAX_DATA_CNT];
unsigned int u32ReadIndex = 0;
unsigned int u32WriteIndex = 0;

int as32Sock[5];
unsigned int u32SockCnt = 0;

static int Filter_AddClient(int s)
{
	int ret = 0;
	
	SM_OsSemWait(&s_u32FilterSockMutex, -1);
	if(u32SockCnt<5)
	{
		as32Sock[u32SockCnt] = s;
		u32SockCnt++;
	}
	SM_OsSemRelease(&s_u32FilterSockMutex);

	return ret;
}

static int Filter_RemoveClient(int s)
{
	unsigned int i;
	
	for(i=0; i<u32SockCnt; i++)
	{
		if(as32Sock[i] == s)
		{
			u32SockCnt--;
			break;
		}
	}
	for(;i<u32SockCnt+1; i++)
		as32Sock[i] = as32Sock[i+1];

	return 0;
}

static int Filter_SendClientData(unsigned char* pu8Ts, unsigned int u32TsLen)
{
	int ret = 0;
	unsigned int i;
	
	SM_OsSemWait(&s_u32FilterSockMutex, -1);
	for(i=0; i<u32SockCnt;)
	{
		if(SM_SockSend(as32Sock[i], pu8Ts, u32TsLen, 0) != SM_SOCK_ERROR)
		{
			i++;
		}
		else
		{
			SM_Printf("Filter_SendClientData send error\r\n");
			Filter_RemoveClient(as32Sock[i]);
			SM_SockClose(as32Sock[i]);
		}
	}
	SM_OsSemRelease(&s_u32FilterSockMutex);

	return ret;
}

unsigned int Filter_RecordTask(void* pParam)
{
	unsigned char* pu8Ts;
	unsigned int u32TsLen;
	int s;
	unsigned int i;

	SM_Printf("Filter_RecordTask entry\r\n");
	while(1)
	{
		if(SM_OsSemWait(&s_u32FilterRecordSemCnt, -1) == 1)
		{
			SM_OsSemWait(&s_u32FilterRecordMutex, -1);
			u32ReadIndex = u32ReadIndex%MAX_DATA_CNT;
			pu8Ts = astData[u32ReadIndex].m_pu8Data;
			u32TsLen = astData[u32ReadIndex].m_u32Len;
			astData[u32ReadIndex].m_u32Len = 0;
			u32ReadIndex++;
			Filter_SendClientData(pu8Ts, u32TsLen);
			SM_OsSemRelease(&s_u32FilterRecordMutex);			
		}
	}
	return 0;
}

unsigned int Filter_ListenTask(void* pParam)
{
	int s;
	int news;
	int len;
	struct SM_SOCKADDR_IN  local;
	struct SM_SOCKADDR  caddr;
	
	SM_Printf("Filter_ListenTask entry\r\n");
	s = SM_SockSOcket(SM_SOCKDOMAIN_AFINET, SM_SOCKTYPE_STREAM, 0);;
	local.sin_addr.net_addr = SM_SockHtonl(SM_INADDR_ANY);
	local.sin_family      = SM_SOCKDOMAIN_AFINET;
	local.sin_port        = SM_SockHtons(51819);
	
	SM_SockBind(s,(struct SM_SOCKADDR *)&local,sizeof(local));
	SM_SockListen(s, 5);
	
	while(1)
	{
		len = sizeof(caddr);
		news = SM_SockAccept(s, (struct SM_SOCKADDR*)&caddr, &len);
		if(news != SM_SOCK_ERROR)
		{
			SM_Printf("Filter_ListenTask acept new socket\r\n");
			Filter_AddClient(news);
		}
		else
		{
			SM_Printf("Filter_ListenTask error %s\r\n", strerror(errno));
			SM_OsThreadSleep(1000);
		}
	}
	return 0;
}

int Filter_RecordInit()
{
	unsigned int hThreadId;
	unsigned int i;

	memset(astData, 0, sizeof(astData));
	SM_OsThreadCreate(0, Filter_ListenTask, NULL, &hThreadId);
	SM_OsThreadCreate(0, Filter_RecordTask, NULL, &hThreadId);
	
	SM_OsSemCreate(&s_u32FilterRecordMutex, NULL, 1);
	SM_OsSemCreate(&s_u32FilterRecordSemCnt, NULL, 0);
	SM_OsSemCreate(&s_u32FilterSockMutex, NULL, 1);
	
	for(i=0; i<MAX_DATA_CNT; i++)
	{
		astData[i].m_pu8Data = SM_OsMemAllocate(0x10000);
	}
	
	return 0;
}

int Filter_RecordWorking(unsigned char* pu8Data, unsigned int u32Len)
{
	unsigned char* pu8Ts;

	if(u8Init == 0)
	{
		Filter_RecordInit();
		u8Init = 1;
	}

	SM_OsSemWait(&s_u32FilterRecordMutex, -1);	
	u32WriteIndex = u32WriteIndex%MAX_DATA_CNT;
	if(astData[u32WriteIndex].m_pu8Data)
	{
		pu8Ts = astData[u32WriteIndex].m_pu8Data;
		memcpy(pu8Ts, pu8Data, u32Len);
		astData[u32WriteIndex].m_u32Len = u32Len;
		u32WriteIndex++;
		if(u32WriteIndex >= u32ReadIndex+MAX_DATA_CNT)
			u32ReadIndex = u32WriteIndex - MAX_DATA_CNT - 1;
		SM_OsSemRelease(&s_u32FilterRecordSemCnt);
	}
	
	SM_OsSemRelease(&s_u32FilterRecordMutex);

	//SM_Printf("Filter_RecordWorking return\r\n");
	return 0;
}

